export class FINode {
  private _children: FINode[] = [];
  private _id: string = '';
  private _parent: FINode | null = null;
  private _childrenMap: { [x in string]?: FINode } = {}

  get id() { return this._id; }
  set id(v: string) {
    this._removeFromMap();
    this._id = v;
    this._addToMap();
  }
  get hasChildren(): boolean { return !!this._children.length; }
  get children(): FINode[] { return this._children; }
  get parent(): FINode | null { return this._parent || null; }

  private set parent(v: FINode | null) {
    this._removeFromMap();
    this._parent = v;
    this._addToMap();
  }
  private _removeFromMap() {
    if (this._id && this._parent) {
      delete this._parent._childrenMap[this._id];
    }
  }
  private _addToMap() {
    if (this._id && this._parent) {
      if (this._parent._childrenMap[this._id]) {
        console.warn('[FINode]id exsits!', this._id)
      }
      this._parent._childrenMap[this._id] = this;
    }
  }


  onAdded() { }

  onRemoved() { }

  addChild(child: FINode) {
    if (child.parent) { return; }
    child.parent = this;
    this.children.push(child);
    this.onAdded();
  }

  removeChild(child: FINode) {
    if (child.parent !== this) { return; }
    const idx = this.children.indexOf(child);
    if (idx < 0) { return; }
    this.children.splice(idx, 1);
    this.onRemoved();
  }

  addChildren(children: FINode[]) {
    children.map(child => this.addChild(child));
  }

  removeChildren(children: FINode[]) {
    children.map(child => this.removeChild(child));
  }

  findChild(id: string): FINode | undefined {
    if (!id) return;
    return this._childrenMap[id]
  }
  update(dt: number) {
    const arr = this.children;
    const len = arr.length;
    for (let i = 0; i < len; ++i) {
      const child = arr[i];
      child.update(dt);
    }
  }

  render(ctx: CanvasRenderingContext2D) {
    const arr = this.children;
    const len = arr.length;
    for (let i = 0; i < len; ++i) {
      const child = arr[i];
      child.render(ctx);
    }
  }
}
